home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
bipl.zip
/
PROGS.ZIP
/
IIDECODE.ICN
< prev
next >
Wrap
Text File
|
1993-01-27
|
7KB
|
253 lines
############################################################################
#
# File: iidecode.icn
#
# Subject: Program to decode text in style of uudecode
#
# Author: Richard L. Goerwitz
#
# Date: June 3, 1991
#
###########################################################################
#
# Version: 1.8
#
###########################################################################
#
# This is an Icon port of the UNIX/C uudecode utility. Since
# uudecode is publicly distributable BSD code, I simply grabbed a
# copy, and rewrote it in Icon. The only basic functional changes I
# made to the program were: 1) To simplify the notion of file mode
# (everything is encoded with 0644 permissions), and 2) to add a
# command-line switch for xxencoded files (similar to uuencoded
# files, but capable of passing unscathed through non-ASCII EBCDIC
# sites).
#
# usage: iidecode [infile] [-x]
#
# Usage is compatible with that of the UNIX uudecode command, i.e. a
# first (optional) argument gives the name the file to be decoded.
# If this is omitted, iidecode just uses the standard input. The -x
# switch (peculiar to iidecode) forces use of the the xxdecoding
# algorithm. If you try to decode an xxencoded file without speci-
# -x on the command line, iidecode will try to forge ahead anyway.
# If it thinks you've made a mistake, iidecode will inform you after
# the decode is finished.
#
# BUGS: Slow. I decided to go for clarity and symmetry, rather than
# speed, and so opted to do things like use ishift(i,j) instead of
# straight multiplication (which under Icon v8 is much faster).
#
############################################################################
#
# See also: iiencode.icn
#
############################################################################
global oversizes
procedure main(a)
local ARG, in, out, dest, is_xx
# Check for correct number of args.
if *a > 2 then {
write(&errout,"usage: iidecode [infile] [-x]")
exit (2)
}
# Check for optional input filename and -x
every ARG := !a do {
if ARG == "-x" then
is_xx := 1
else {
if not (in := open(ARG, "r")) then {
write(&errout,"Can't open input file, ",a[1],".")
write(&errout,"usage: iidecode [infile] [-x]")
exit(1)
}
}
}
/in := &input
# Find the "begin" line, and determine the destination file name.
!in ? {
tab(match("begin ")) &
tab(many(&digits)) & # mode ignored
tab(many(' ')) &
dest := trim(tab(0),'\r') # concession to MS-DOS
}
# If dest is null, the begin line either isn't present, or is
# corrupt (which necessitates our aborting with an error msg.).
if /dest then {
write(&errout,"No begin line.")
exit(3)
}
# Tilde expansion is heavily UNIX dependent, and we can't always
# safely write the file to the current directory. Our only choice
# is to abort.
if match("~",dest) then {
write(&errout,"Please remove ~ from input file begin line.")
exit(4)
}
out := open(dest, "wu")
decode(in, out, is_xx) # decode checks for "end" line
if not match("end", !in) then {
write(&errout,"No end line.\n")
exit(5)
}
# Check global variable oversizes (set by DEC) to see if we used the
# correct decoding algorithm.
if \is_xx then {
if oversizes = 0 then {
write(&errout, "Input file appears to have been uuencoded.")
write(&errout, "Try invoking iidecode without the -x arg.")
}
}
else {
if oversizes > 1 then {
write(&errout, "Input file is either corrupt, or xxencoded.")
write(&errout, "Please check the output; try the -x option.")
}
}
every close(\in | out)
exit(0)
end
procedure decode(in, out, is_xx)
# Copy from in to out, decoding as you go along.
local line, chunk, n
if \is_xx then
DEC := xxDEC
while line := read(in) do {
if *line = 0 then {
write(&errout,"Short file.\n")
exit(10)
}
line ? {
n := DEC(ord(move(1)))
if not ((*line-1) % 4 = 0, n <= ((*line / 4)*3)) then {
write(&errout,"Short and/or corrupt line:\n",line)
if /is_xx & oversizes > 1 then
write(&errout,"Try -x option?")
exit(15)
}
# Uuencode signals the end of the coded text by a space
# and a line (i.e. a zero-length line, coded as a space).
if n <= 0 then break
while (n > 0) do {
chunk := move(4) | tab(0)
outdec(chunk, out, n)
n -:= 3
}
}
}
return
end
procedure outdec(s, f, n)
# Output a group of 3 bytes (4 input characters). N is used to
# tell us not to output all of the chars at the end of the file.
local c1, c2, c3
c1 := iand(
ior(
ishift(DEC(ord(s[1])),+2),
ishift(DEC(ord(s[2])),-4)
),
8r0377)
c2 := iand(
ior(
ishift(DEC(ord(s[2])),+4),
ishift(DEC(ord(s[3])),-2)
),
8r0377)
c3 := iand(
ior(
ishift(DEC(ord(s[3])),+6),
DEC(ord(s[4]))
),
8r0377)
if (n >= 1) then
writes(f,char(c1))
if (n >= 2) then
writes(f,char(c2))
if (n >= 3) then
writes(f,char(c3))
end
procedure DEC(c)
# global oversizes
initial oversizes := 0
# Count characters lexically greater or equal to 'a.'
# If we get a lot of these, the file is corrupt, or perhaps
# xxencoded (in which case -x should have been specified).
if c >= 97 then
oversizes +:= 1
# Subtract 32 and mask off seventh and higher bits.
return iand(c - 32, 8r077)
end
procedure xxDEC(c)
local k, ordval, new_c
static ordtbl
# global oversizes
initial {
ordval := -1
ordtbl := table()
every k := ord(!"+-0123456789ABCDEFGHIJKLMNOPQRST_
UVWXYZabcdefghijklmnopqrstuvwxyz")
do insert(ordtbl, k, ordval +:= 1)
oversizes := 0
}
# Mask off eighth and higher bits.
new_c := iand(c, 8r177)
# Count characters lexically greater or equal to 'a.'
# If we find none of these, the file probably wasn't xxencoded.
if new_c >= 97 then
oversizes +:= 1
# Map to 0-63 range (00111111 or less), mask off extra bits.
return iand(\ordtbl[new_c], 8r077) |
stop("Garbled or non-xxencoded file.")
end